﻿using System.Collections.Generic;
using System.Linq;
using CardPlay.Model.ActionModel;
using CardPlay.Model.CardModel;
using CardPlay.Model.GameModel;
using CardPlay.Model.GameModel.Actions;
using CardPlay.Model.GameModel.Presentation;
using CardPlay.Model.Layout;
using CardPlay.Model.Primitives;

namespace CardPlay.DemoPack.Games
{
    [Game("A510A487-ADE4-443B-A022-9D6D707C698C", LevelOfDifficulty.Easy, LevelOfSkill.MostlyChance, DurationOfPlay.LessThan5Minutes)]
    public class RoyalMarriage : StandardCardGame
    {
        public RoyalMarriage()
        {
            MaximumDeals = 1;
            CardsPerDeal = 1;
        }

        public override ILayoutSite CreatePresentation(IPresentationContext presentation)
        {
            var metrics = presentation.Metrics;

            var root = new GridLayout
                       {
                           Columns = 1,
                           Rows = 2,
                           HorizontalContentAlignment = HorizontalAlignment.Center,
                           MinimumSize = new Size(metrics.CardSize.Width * 5, metrics.CardSize.Height)
                       };


            {
                var stockStyle = new VisualTraits
                {
                    Arrangement = CardArrangement.StackTower,
                    MinimumSize = new Size(metrics.CardSize.Width, metrics.CardSize.Height * 9 / 8),
                    HorizontalAlignment = HorizontalAlignment.Center
                };

                var layout = presentation.CreatePileVisual(Stock, stockStyle);

                root.Add(layout);
            }

            {
                var wasteStyle = new VisualTraits
                {
                    Arrangement = CardArrangement.StackLeftToRight,
                    ContentFit = ContentFit.FitWidth
                };

                var layout = presentation.CreatePileVisual(Waste, wasteStyle);

                root.Add(layout);
            }

            return root;
        }

        public override int PercentComplete
        {
            get
            {
                const int endCount = 2;

                var initialCount = CardFace.CardsPerStandardDeck;
                var currentCount = CardPiles.Aggregate(0, (total, pile) => total + pile.Count);

                return 100 - (100 * (currentCount - endCount) / (initialCount - endCount));
            }
        }

        protected override bool IsComplete
        {
            get
            {
                return this[Stock].IsEmpty && this[Waste].Count == 2;
            }
        }

        protected override bool IsOver
        {
            get
            {
                return this[Stock].IsEmpty && !IsRemovePossible;
            }
        }

        protected override IEnumerable<string> InitialPileNames
        {
            get
            {
                return new[] { Stock, Waste };
            }
        }
    
        protected override void PrepareDealScript(DealScript script)
        {
            script.Deal("face(hearts queen) up").To(Waste);
            script.Deal("face(hearts king) down").To(Stock);
            script.DealRemainingFaceDownTo(Stock);
        }

        protected override IAction QueryActionAt(PartLocation location)
        {
            var card = CardAt(location);

            if (card != null)
            {
                if (location.Path == Waste)
                {
                    var removalSet = GetCardsToBeRemovedAt(location.Index);

                    if (removalSet != null)
                    {
                        var removeAction = new ComplexAction();

                        foreach (var action in removalSet.Select(o => new RemoveCardAction(this, new PartLocation(Waste, removalSet[0]))))
                        {
                            removeAction.Add(action);
                        }

                        return removeAction;
                    }
                }
                else if (!IsRemovePossible)
                {
                    return base.QueryActionAt(location);
                }
            }

            return null;
        }

        static private bool SameSuitOrRank(CardFace card1, CardFace card2)
        {
            return card1.Rank == card2.Rank || card1.Suit == card2.Suit;
        }

        private bool IsRemovePossible
        {
            get
            {
                var count = this[Waste].Count;
                return count > 1 && Enumerable.Range(1, count).Any(i => GetCardsToBeRemovedAt(i) != null);
            }
        }

        private int[] GetCardsToBeRemovedAt(int position)
        {
            var wastePile = this[Waste];

            if (position > 0 && position < wastePile.TopIndex)
            {
                var prevCard = wastePile.CardAt(position - 1);
                var nextCard = wastePile.CardAt(position + 1);

                if (SameSuitOrRank(prevCard, nextCard))
                    return new[] { position };
                
                if (position > 1 && SameSuitOrRank(wastePile.CardAt(position - 2), nextCard))
                    return new[] { position - 1, position };
                
                if (position < wastePile.TopIndex - 1 && SameSuitOrRank(prevCard, wastePile.CardAt(position + 2)))
                    return new[] { position, position + 1 };
            }

            return null;
        }
    }
}